package main

import "fmt"

func main() {

	var n []int           //MARK nil
	fmt.Println(n == nil) //ture
	printSlice2("n", nil) //n len=0 cap=0 [] MARK nil切片 和空切片不同 都没初始化数据结构

	var p *[]int = new([]int) //MARK 得到一个指向 []int类型的nil的指针
	fmt.Println(*p == nil)    //ture

	sliceFromBase()
	literals()

	makeSlices()

	add()
	len_cap()
}

func len_cap() {
	fmt.Println("==============长度容量 ==============")
	s := []int{0, 1, 2, 3, 4, 5}
	printSlice(s)

	// 截取切片使其长度为 0
	s1 := s[:0] //len=0 cap=6 [] MARK 后面截 容量不会变, 长度也能再回复
	printSlice(s1)

	// 拓展其长度
	s2 := s1[:4] //len=4 cap=6 [0 1 2 3]  MARK  长度也能再回复
	printSlice(s2)

	// 舍弃前两个值
	s = s[2:] //len=4 cap=4 [2 3 4 5] MARK 截前面 容量就有损失了
	printSlice(s)

	var n []int // len=0 cap=0 [] MARK nil切片 虽然如此 make([]int,0) != nil
	printSlice(n)
	if n == nil {
		//MARK 确实成立
		fmt.Println("nil!")
	}
}

func add() {
	var s []int
	printSlice2("", s) //len=0 cap=0 []

	fmt.Println("==========原切片数组不够放,用新切片==========")
	// 添加一个空切片 MARK 不够时 原切片不变 是生成一个新的切片
	s1 := append(s, 0) //len=1 cap=1 [0]
	printSlice2("", s1)

	fmt.Println("==========原切片数组够放,用原切片数组==========")
	n := make([]int, 1, 5) //len=1 cap=5 [0]
	s2 := append(n, 1)     //len=1 cap=5 [1] MARK 容量够(就是原底层数组有) 直接用原切片的数据
	printSlice2("", s2)
	s2[0] = 99
	printSlice2("", n) //len=1 cap=5 [99] MARK 原切片这个值也变了 证明是同一个数组

	fmt.Println("==========切片合并==========")
	p1 := []int{1, 2, 3}
	p2 := []int{4}
	printSlice2("", append(p1, p2...)) //MARK 可变参数本质是切片, 这里...语法题 直接传切片
}

func makeSlices() {

	fmt.Println("==============make 来指定大小创建切片 ==============")

	//MARK 没有作为基础的切片和数组 也没有字面量时  mark来创建空切面 ,值都初始化为元素对应零值
	a := make([]int, 5) //len=5 cap=5 [0 0 0 0 0] MARK 给一个数字就是长度和容量
	printSlice2("a", a)

	b := make([]int, 0, 5) //len=0 cap=5 []
	printSlice2("b", b)

	c := make([]int, 0) //len=0 cap=0 []  MARK 是空切片 和nil切片 长度,容量 一样 但是不== 一个是空的切片, 一个就是nil以切片的面貌出现
	printSlice2("c", c)

}
func printSlice2(name string, x []int) {
	fmt.Printf("%s len=%d cap=%d %v\n",
		name, len(x), cap(x), x)
}

func literals() {

	fmt.Println("==============字面量初始化 ==============")

	//MARK 切片字面量
	r := []bool{true, false, true, true, false, true} //MARK 和数组几乎一样 除了没指定大小
	fmt.Println(r)

	s := []struct {
		i int
		b bool
	}{
		{2, true},
		{3, false},
	}
	fmt.Println(s) //[{2 true} {3 false}]

	type abc struct {
		a, b, c int
	}
	s2 := []abc{
		{1, 1, 1},
		{1, 2, 3},
	}
	fmt.Println(s2) //[{1 1 1} {1 2 3}]
}

func sliceFromBase() {
	fmt.Println("==============从数组或者其他切片 切来的 ==============")
	primes := [6]int{0, 1, 2, 3, 4, 5} //MARK 数组(本质是有固定大小)

	//切片的类型 []int 就是数组里面去掉数字, 这里[]int 可以不写,赋值已经能得到类型了
	var s []int = primes[1:4] //MARK 从数组得到切片 访问是 [1,4)
	//MARK 切片并不存储任何数据，它只是描述了底层数组中的一段。修改 改的是原数值
	s[0] = 99

	fmt.Println(s)      //[99 2 3]
	fmt.Println(primes) //[0 99 2 3 4 5]

	s1 := []int{0, 1, 2, 3, 4, 5}
	fmt.Println(s1[1:4]) //切[1,4) [1 2 3]得 MARK 切片能从数组切得也能
	fmt.Println(s1[:2])  //切[0,2)得 [0 1]
	fmt.Println(s1[1:])  //切[1,无限) 得[1 2 3 4 5]
	//fmt.Println(s1[1:99]) //MARK 不够切会报错
}
